package me.hacklh.obfuscator;


import me.hacklh.utils.FileUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class VmObfuscator {

    private static String[] lines;
    private static String[] command_lines;

    /**
     * 混淆的主要函数，返回处理后的文本
     *
     * @param content  待处理的文本内容
     * @param commands 存储混淆指令的文本内容
     * @return
     */
    public static String confuse(String content, String commands) {

        String obfuseContent = "";

        // 首先将文本切割, 同时将混淆指令按行打散，存入command_lines
        lines = getLines(content);
        command_lines = getLines(commands);


        // 使用正则表达式找混淆指令
        String regEx = "^@@(.*?)";
        Pattern pattern = Pattern.compile(regEx);
        String command = "";
        for (int i = 0; i < command_lines.length; i++) {
            command = command_lines[i];
            Matcher matcher = pattern.matcher(command);

            // 如果找到混淆指令，进入处理流程
            if (matcher.matches()) {
                handleCommand(command);
            }
        }
        for (String line : lines) {
            if (line != "") {
                obfuseContent += line;
                obfuseContent += "\n";
            }
        }

        return deleteCRLF(obfuseContent);
    }

    /***
     * delete CRLF; delete  empty line ;delete blank lines
     *
     * @param input
     * @return
     */
    private static String deleteCRLFOnce(String input) {

        return input.replaceAll("((\r\n)|\n)[\\s\t ]*(\\1)+", "$1");

    }

    /**
     * delete CRLF; delete  empty line ;delete blank lines
     *
     * @param input
     * @return
     */
    public static String deleteCRLF(String input) {
        input = deleteCRLFOnce(input);
        return deleteCRLFOnce(input);
    }

    /**
     * 把文件内容按换行符切割为列表
     *
     * @param content
     * @return
     */
    public static String[] getLines(String content) {
        String[] line_s;
        line_s = content.split("\n|\r\n");
        return line_s;
    }


    /**
     * 处理我们自定义的命令
     *
     * @param command
     */
    public static void handleCommand(String command) {

        // 将识别命令的正则放到数组中
        List patterns = new ArrayList();
        patterns.add(Pattern.compile("^@@(replace) (\\[.*?\\]) \"(.*?)\" \"(.*?)\"")); // replace命令
        patterns.add(Pattern.compile("^@@(remove) (\\[.*?\\])")); // remove命令
        patterns.add(Pattern.compile("^@@(remove_space) (\\[.*?\\])")); // remove_space命令
        patterns.add(Pattern.compile("^@@(add) (\\[.*?\\]) \"(.*?)\"")); // add命令
        patterns.add(Pattern.compile("^@@(remove_comment) (\\[.*?\\])")); // remove_comment命令
        patterns.add(Pattern.compile("^@@(remove_endline) (\\[.*?\\])")); // remove_endline命令

        for (int i = 0; i < patterns.size(); i++) {
            Pattern pattern = (Pattern) patterns.get(i);
            Matcher m = pattern.matcher(command);
            if (m.find()) {
                doAction(i, command);
            }
        }

    }

    /**
     * 具体的混淆命令的操作实现
     *
     * @param commandId
     * @param command
     */
    public static void doAction(int commandId, String command) {
        switch (commandId) {
            case 0:
                replaceString(command);
                break;
            case 1:
                removeString(command);
                break;
            case 2:
                remove_space(command);
                break;
            case 3:
                add(command);
                break;
            case 4:
                remove_comment(command);
                break;
            case 5:
                remove_endline(command);
                break;
        }


    }

    private static void remove_comment(String command) {

        // 表示模板指令的表达式
        Pattern template_i = Pattern.compile("^#");
        // 提取参数的表达式
        Pattern arg_exp = Pattern.compile("^@@(remove_comment) (\\[.*?\\])");
        Matcher m = arg_exp.matcher(command);
        if (m.find() != true) {
            return;
        }

        // 拿到操作的范围
        Pattern range = Pattern.compile("\\[(.*?)-(.*?)\\]");
        String rg = m.group(2);
        Matcher rangeM = range.matcher(rg);
        if (rangeM.find() != true) {
            return;
        }

        int start = Integer.parseInt(rangeM.group(1));
        int end = Integer.parseInt(rangeM.group(2));

        for (int i = start - 1; i < end; i++) {
            String line = lines[i];
            Matcher matcher = template_i.matcher(line);
            // 如果是模板指令，处理下一行
            if (matcher.find()) {
                continue;
            }
            line = line.replaceAll("//.*", "");
            lines[i] = line;
        }

    }

    private static void add(String command) {
        // 提取参数的表达式
        Pattern arg_exp = Pattern.compile("^@@(add) (\\[.*?\\]) \"(.*?)\"");
        Matcher m = arg_exp.matcher(command);
        if (m.find() != true) {
            return;
        }

        // 表示模板指令的表达式
        Pattern template_i = Pattern.compile("^#");

        Pattern range = Pattern.compile("\\[(.*?)\\]");
        String rg = m.group(2);
        Matcher rangeM = range.matcher(rg);
        if (rangeM.find() != true) {
            return;
        }

        int index = Integer.parseInt(rangeM.group(1));
        List<String> listA = Arrays.asList(lines);
        List<String> list = new ArrayList<String>(listA);
        list.add(index - 1, m.group(3));

        lines = list.toArray(new String[list.size()]);

    }


    private static void remove_space(String command) {
        // 提取参数的表达式
        Pattern arg_exp = Pattern.compile("^@@(remove_space) (\\[.*?\\])");
        Matcher m = arg_exp.matcher(command);
        if (m.find() != true) {
            return;
        }

        // 表示模板指令的表达式
        Pattern template_i = Pattern.compile("^#");

        Pattern range = Pattern.compile("\\[(.*?)-(.*?)\\]");
        String rg = m.group(2);
        Matcher rangeM = range.matcher(rg);
        if (rangeM.find() != true) {
            return;
        }

        int start = Integer.parseInt(rangeM.group(1));
        int end = Integer.parseInt(rangeM.group(2));

        for (int i = start - 1; i < end; i++) {
            String line = lines[i];
            Matcher matcher = template_i.matcher(line);
            // 如果是模板指令，处理下一行
            if (matcher.find()) {
                continue;
            }

            // 剔除空白字符
            Pattern space_exp = Pattern.compile("^#");

            line = line.replace(", ", ",");
            line = line.replace("\t", "");

            line = line.replaceAll("^\\s*", "");
            line = line.replaceAll(";\\s*", ";");
            line = line.replaceAll("\\{\\s*", "{");
            line = line.replaceAll("\\)\\s*\\{", "){");

            String[] key_words = {"while", "if", "else if"};
            for (String key_word : key_words
                    ) {
                String regex = key_word + "\\s\\(";
                line = line.replaceAll(regex, key_word + "(");

            }
            //去掉 < .

            String[] key_words2 = {"\\)", "<", ">", "=", "==", "!=", "&&", "<<", ">>", "\\|\\|", "<=", ">=", "\\+", "-", "/", "\\*"};
            for (String key_word : key_words2
                    ) {
                String regex = "\\s*" + key_word + "\\s*";
                line = line.replaceAll(regex, key_word);
            }
            lines[i] = line;

        }

    }

    public static String getStringNoBlank(String str) {
        if (str != null && !"".equals(str)) {
            Pattern p = Pattern.compile("\\s*|\t");
            Matcher m = p.matcher(str);
            String strNoBlank = m.replaceAll("");
            return strNoBlank;
        } else {
            return str;
        }
    }

    private static void remove_endline(String command) {
        // 提取参数的表达式
        Pattern arg_exp = Pattern.compile("^@@(remove_endline) (\\[.*?\\])");
        Matcher m = arg_exp.matcher(command);
        if (m.find() != true) {
            return;
        }

        // 表示模板指令的表达式
        Pattern template_i = Pattern.compile("^#");

        Pattern range = Pattern.compile("\\[(.*?)-(.*?)\\]");
        String rg = m.group(2);
        Matcher rangeM = range.matcher(rg);
        if (rangeM.find() != true) {
            return;
        }

        int start = Integer.parseInt(rangeM.group(1));
        int end = Integer.parseInt(rangeM.group(2));

        String tmp_content = "";
        int i;
        for (i = start - 1; i < end; i++) {
            String line = lines[i];
            Matcher matcher = template_i.matcher(line);
            // 如果是模板指令，处理下一行
            if (matcher.find()) {
                lines[i - 1] = tmp_content;
                tmp_content = "";
                continue;
            }

            tmp_content += line;
            lines[i] = "";
        }
        if (tmp_content != "") {
            lines[i - 1] = tmp_content;
            tmp_content = "";
        }

    }

    private static void removeString(String command) {

        // 表示模板指令的表达式
        Pattern template_i = Pattern.compile("^#");
        // 提取参数的表达式
        Pattern arg_exp = Pattern.compile("^@@(remove) (\\[.*?\\])");
        Matcher m = arg_exp.matcher(command);
        if (m.find() != true) {
            return;
        }

        // 拿到操作的范围
        Pattern range = Pattern.compile("\\[(.*?)-(.*?)\\]");
        String rg = m.group(2);
        Matcher rangeM = range.matcher(rg);
        if (rangeM.find() != true) {
            return;
        }

        int start = Integer.parseInt(rangeM.group(1));
        int end = Integer.parseInt(rangeM.group(2));

        for (int i = start - 1; i < end; i++) {
            Matcher matcher = template_i.matcher(lines[i]);
            // 如果是模板指令，处理下一行
            if (matcher.find()) {
                continue;
            }
            lines[i] = "";
        }

    }

    private static void replaceString(String command) {
        // 提取参数的表达式
        Pattern arg_exp = Pattern.compile("@@(.*?) (\\[.*?\\]) \"(.*?)\" \"(.*?)\"");
        Matcher m = arg_exp.matcher(command);
        if (m.find() != true) {
            return;
        }

        // 表示模板指令的表达式
        Pattern template_i = Pattern.compile("^#");

        Pattern range = Pattern.compile("\\[(.*?)-(.*?)\\]");
        String rg = m.group(2);
        Matcher rangeM = range.matcher(rg);
        if (rangeM.find() != true) {
            return;
        }

        int start = Integer.parseInt(rangeM.group(1));
        int end = Integer.parseInt(rangeM.group(2));

        for (int i = start - 1; i < end; i++) {
            String line = lines[i];
            Matcher matcher = template_i.matcher(line);
            // 如果是模板指令，处理下一行
            if (matcher.find()) {
                continue;
            }

            lines[i] = line.replace(m.group(3), m.group(4));

        }
    }

    public static void main(String[] args) throws Exception {
        String private_key = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKAiKDxq2Ly6/gBjz+c1VIjH4UQS2z2doOCMqSncwmMcMN689x7e5A7Bo8c4MOyiUOgy4fBzqZy6rScJVjbkj9kTQaw04PKQ/iCSmgIKmEIXsE2EJCBrr197VmW+yoiEB9+tdxLo1OPl20EPFai3k1a9oXi2vmwDtejsrlfomBHbAgMBAAECgYEAlRY4D8gKcexGf2ZuMfzc71voxtAnfn47QdSzyl3WPSAJ/9Y+3Wb3PSXbracLJcUZPpXg9VU6HMlQXH+83O5/XUU3IuRJxoROxMfZvRBYu4VaKbRrYA7np4SDwHzxoto/GZY9sm641rRZNoh3T/bKeUQ+zoRw6zVaSUbZVcTGb0ECQQDt+JGwK1uHAfZc6L5qHFtTBth2hmilvGfnTbyPa7bMPVUf33MLVd/jDkXlfvF0TLTS0X8oJihYKtnDSws5+S6lAkEArEPvI1nyJHIS9HtfLMt3vktYU9ijn+vTCsXhEVq5orRFhWfKpFrX6xqsAlw+b9cHWx7XRgeZzheRY5QeAEzWfwJAPQGJT9F9sFm3b9AW6JsGan2JxrDkaQCo3mpWWaoyfZ+HkBk3pANK1ymUj6YAfmEfxiAA6ikGFLw/gUpewWj5JQJAS1zA/sc3zsf1EO30OkWdUivmLXBGTQ0/W6QsDYqSUeLp0y4QEg0IDvuxKqsuSYFZ33xDk4h5uhbHbTf8VAdJgwJBAKfjRZ6L+r8Ykq43amYA3DiQbd7qW9BKJ0BpStxmSFlGaUP7huoy4OJmENcHWtxS0Q+jXc/Dz22Vyocwt9hjzh8=";
        String public_key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCgIig8ati8uv4AY8/nNVSIx+FEEts9naDgjKkp3MJjHDDevPce3uQOwaPHODDsolDoMuHwc6mcuq0nCVY25I/ZE0GsNODykP4gkpoCCphCF7BNhCQga69fe1ZlvsqIhAffrXcS6NTj5dtBDxWot5NWvaF4tr5sA7Xo7K5X6JgR2wIDAQAB";

        FileUtils.encryptFile(public_key, "C:\\Users\\Administrator\\IdeaProjects\\obfuscator\\src\\xsk.vm", "f:\\encode.txt");

        String vm_content = FileUtils.decodeFile(private_key, "f:\\encode.txt");
        String commands = FileUtils.getFileContent("C:\\Users\\Administrator\\IdeaProjects\\obfuscator\\src\\command.txt");
        String content = confuse(vm_content, commands);
        System.out.println("---------------------------------");
        System.out.println(content);
    }

}
